'''给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为：“对于有根树T的两个结点p、q，最近公共祖先表示为一个结点x，满足x是p、q的祖先且x的深度尽可能大（一个节点也可以是它自己的祖先）。”

例如，给定如下二叉树: root = [3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]

示例
1:

输入: root = [3, 5, 1, 6, 2, 0, 8, null, null, 7, 4], p = 5, q = 1
输出: 3



示例
2:

输入: root = [3, 5, 1, 6, 2, 0, 8, null, null, 7, 4], p = 5, q = 4
输出: 5




说明:

所有节点的值都是唯一的。p、q为不同节点且均存在于给定的二叉树中。
'''
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None



'''递归解析：

终止条件：

当越过叶节点，则直接返回 null ；
当 root 等于 p,q ，则直接返回 root ；


递推工作：

开启递归左子节点，返回值记为 left ；
开启递归右子节点，返回值记为 right；


返回值： 根据 left 和 right，可展开为四种情况；

1.当 left 和 right 同时为空 ：说明 root 的左 / 右子树中都不包含 p,q，返回 null；
2. left 和 right 同时不为空 ：说明 p,q 分列在 root 的 异侧 （分别在 左 / 右子树），因此 root 为最近公共祖先，返回 root ；
3.当 left 为空 ，right 不为空 ：p,q 都不在 root 的左子树中，直接返回 right 。具体可分为两种情况：

p,q 其中一个在 root 的 右子树 中，此时 right 指向 p（假设为 p ）；
p,q 两节点都在 root 的 右子树 中，此时的 right 指向 最近公共祖先节点 ；


4.当 left 不为空 ， right 为空 ：与情况 3. 同理；

'''
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root or root==p or root ==q:
            return root
        left=self.lowestCommonAncestor(root.left,p,q)
        right=self.lowestCommonAncestor(root.right,p,q)
        if not left and not right:#左右都为空，则不是这个节点
            return
        if not left:#左子树为空，则应该在右边
            return right
        if not right:#右子树为空，则应该在左边
            return left
        return root#左右都不为空，则pq在root两端，返回root即可



#很久之前做过这个题，当时用的是非递归方法，根据路径，最后一个重复节点即为最近公共祖先
#但记不太清怎么写了，这里直接粘贴过来
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        self.paths = []
        def findPath(childroot, cur):
            if not childroot or len(self.paths) == 2:
                return
            cur = cur + [childroot]
            if childroot == p or childroot == q:
                self.paths.append(cur)
            findPath(childroot.left, cur)
            findPath(childroot.right, cur)
        findPath(root, [])
        res = None
        mmin = min(len(self.paths[0]), len(self.paths[1]))
        for i in range(mmin):
            if self.paths[0][i] == self.paths[1][i]:
                res = self.paths[0][i]
            else:
                break
        return res

